﻿using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
using WinForms.Framework.Utility;

namespace WinForms.Framework.DataAnnotations
{
    /// <summary>
    /// 数字検証
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class DigitsAttribute : DataTypeAttribute
    {
        /// <summary>
        /// 検証失敗時に出力するエラーメッセージ
        /// </summary>
        private const string ERROR_MESSAGE = "{0}は数値で入力してください。";

        /// <summary>
        /// 項目名
        /// </summary>
        private string _displayName;

        /// <summary>
        /// NumericAttribute クラスのインスタンスを生成します。
        /// </summary>
        public DigitsAttribute()
            : base("digits")
        {
            ErrorMessage = ERROR_MESSAGE;
        }

        /// <summary>
        /// エラーが発生したデータ フィールドに基づいて、エラー メッセージに書式を適用します。
        /// </summary>
        /// <param name="name">書式設定されたメッセージに含める名前。</param>
        /// <returns>書式設定されたエラー メッセージのインスタンス。</returns>
        public override string FormatErrorMessage(string name)
        {
            return string.Format(ErrorMessageString, _displayName);
        }

        /// <summary>
        /// データ フィールドの値が有効かどうかをチェックします。
        /// </summary>
        /// <param name="value">検証対象の値。</param>
        /// <returns>検証結果。成功時：true. 失敗時：false.</returns>
        public override bool IsValid(object value)
        {
            if (string.IsNullOrEmpty(value?.ToString()))
                return true;

            Regex expression = new Regex(@"^[0-9]*$");
            if (value is string)
                return expression.IsMatch((string)value);
            else
                return expression.IsMatch(value.ToString());
        }

        /// <summary>
        /// 現在の検証属性に対して、指定した値を検証します。
        /// </summary>
        /// <param name="value">検証対象の値。</param>
        /// <param name="validationContext">検証操作に関するコンテキスト情報。</param>
        /// <returns>System.ComponentModel.DataAnnotations.ValidationResult クラスのインスタンス。</returns>
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var property = validationContext.ObjectType.GetProperty(validationContext.MemberName);
            _displayName = Attributer.HasAttribute(property, typeof(DisplayNameAttribute))
                ? Attributer.GetAttribute<DisplayNameAttribute>(property).DisplayName
                : validationContext.DisplayName;

            if (IsValid(value))
                return ValidationResult.Success;
            else
                return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
        }
    }
}